#include"route_lb.h"
#include"main_server.h"

route_lb::route_lb(int id){
    this->_id = id;

    // 锁初始化
    pthread_mutex_init(&_mutex, NULL);
}

// 根据modid和cmdid获取host信息的方法
int route_lb::get_host(int modid, int cmdid, lars::GetHostResponse &response){
    printf("route_lb::get_host\n");
    // 设置函数返回值
    int ret = lars::RET_SUCC;
    
    // 1.组装key
    uint64_t mod = (((uint64_t)modid) << 32) + cmdid;
    
    // 加锁
    pthread_mutex_unlock(&_mutex);
    pthread_mutex_lock(&_mutex);
    
    // 2.查找当前map中是否存在对应key的数据
    if(_route_lb_map.find(mod) != _route_lb_map.end()){
        // 3.找到了对应的load_balance信息，获取可用的所有host信息
        
        // 取出对应的load_balance对象
        load_balance* lb = _route_lb_map[mod];
        if(lb->empty()){
            // 说明当前的lb模块没有任何的host信息, 说明正在pulling中
            if(lb->_status == load_balance::PULLING){
                response.set_retcode(lars::RET_NOEXIST);
            }
        }
        else{
            // 说明当前的lb模块下有host信息
            ret = lb->choice_one_host(response);
            response.set_retcode(ret);
            // 触发超时重新拉取机制
            if(lb->_status == load_balance::NEW && (time(NULL)-lb->_last_update_time) > config.lb_update_timeout){
                lb->pull();
                printf("time out try again pull!\n");

            }

        }

    }
    else{
        // 4.未找到，
        // 4.1.新建一个load_balance模块
        load_balance* lb = new load_balance(modid, cmdid);
        if (lb == NULL) {
            fprintf(stderr, "no more space to create loadbalance\n");
            exit(1);
        }

        // 4.2.让load_balance从dns service拉取当前的mod模块所对应的host主机信息
        lb->pull();

        // 4.3.将当前的mod和load_balance加入到map中
        _route_lb_map[mod] = lb;

        // 4.4.当前这一次访问是失败的, 设置rsp的回执retcode
        response.set_retcode(lars::RET_NOEXIST);

        ret = lars::RET_NOEXIST;
    }

    // 解锁
    pthread_mutex_unlock(&_mutex);

    return ret;
}

//根据Dns Service返回的结果更新自己的route_lb_map
int route_lb::update_host(int modid, int cmdid, lars::GetRouteResponse &response){
    // 1.得到mod模块
    uint64_t mod = (((uint64_t)modid)<<32) + cmdid;
    
    // 加锁
    pthread_mutex_lock(&_mutex);
    
    // 2.找到对应的load_balance集合
    if(_route_lb_map.find(mod) != _route_lb_map.end()){
        // 取出对应的load_balance对象
        load_balance* lb = _route_lb_map[mod];
        
        if(response.host_size() == 0){
            // 表示dns返回的结果中当前的mod下没有host，则删除当前的key value对

            delete lb;
            _route_lb_map.erase(mod);
        }
        else{
            // 表示当前mod下有host信息
            // 将当前的response中的host信息加入到load_balance中
            lb->update(response);
        }



    }
    else{
        printf("not have modid:%d, cmdid:%d data insert\n", modid, cmdid);
    }

    // 解锁
    pthread_mutex_unlock(&_mutex);

    return 0;
}

// 将全部的load_balance重置为NEW状态 
void route_lb::reset_lb_status(){
    // 加锁
    pthread_mutex_lock(&_mutex);

    // 循环遍历每一个load_balance，将其的状态设置为NEW
    for(Route_map_it it=_route_lb_map.begin(); it!=_route_lb_map.end(); it++){
        load_balance* lb = it->second;
        
        if (lb->_status == load_balance::PULLING) {
            lb->_status = load_balance::NEW;
        }
    }

    // 解锁
    pthread_mutex_unlock(&_mutex);
}

// 根据agent给的消息上报host调用结果
void route_lb::report_host(lars::ReportRequest &request){
    // 1.获取数据中的信息
    int modid = request.modid();
    int cmdid = request.cmdid();
    int retcode = request.retcode();
    int ip = request.host().ip();
    int port = request.host().port();

    // 2.组装key
    uint64_t mod = (((uint64_t)modid) << 32) + cmdid;
    
    // 3.使用map前加锁
    pthread_mutex_lock(&_mutex);

    // 4.通过请求的mod找到对应的load_balance
    if(_route_lb_map.find(mod) != _route_lb_map.end()){
        load_balance* lb = _route_lb_map[mod];

        // lb处理当前的上报请求
        // 4.1通过对当前主机的上报结果，调整内部的节点idle和overload列表的关系
        lb->report(ip, port, retcode);

        // 4.2再将最终的结果上报给远程的reporter service
        lb->commit();

    }

    // 5.解锁
    pthread_mutex_unlock(&_mutex);
    
}


// 根据agent发过来的消息，加载当前modid和cmdid下的全部host信息
int route_lb::get_route(int modid, int cmdid, lars::GetRouteResponse &response){

    printf("route_lb::get_route\n");
    // 设置函数返回值
    int ret = lars::RET_SUCC;
    
    // 1.组装key
    uint64_t mod = (((uint64_t)modid) << 32) + cmdid;
    
    // 加锁
    pthread_mutex_unlock(&_mutex);
    pthread_mutex_lock(&_mutex);
    
    // 2.查找当前map中是否存在对应key的数据
    if(_route_lb_map.find(mod) != _route_lb_map.end()){
        // 3.找到了对应的load_balance信息，获取可用的所有host信息
        
        // 取出对应的load_balance对象
        load_balance* lb = _route_lb_map[mod];
        if(lb->empty()){
            // 说明当前的lb模块没有任何的host信息, 说明正在pulling中
            return lars::RET_NOEXIST;
        }
        else{
            // 说明当前的lb模块下有host信息
            lb->get_all_hosts(response);
            
            // 触发超时重新拉取机制
            if(lb->_status == load_balance::NEW && (time(NULL)-lb->_last_update_time) > config.lb_update_timeout){
                lb->pull();
                printf("time out try again pull!\n");

            }

        }

    }
    else{
        // 4.未找到，
        // 4.1.新建一个load_balance模块
        load_balance* lb = new load_balance(modid, cmdid);
        if (lb == NULL) {
            fprintf(stderr, "no more space to create loadbalance\n");
            exit(1);
        }

        // 4.2.让load_balance从dns service拉取当前的mod模块所对应的host主机信息
        lb->pull();

        // 4.3.将当前的mod和load_balance加入到map中
        _route_lb_map[mod] = lb;

        ret = lars::RET_NOEXIST;
    }

    // 解锁
    pthread_mutex_unlock(&_mutex);

    return ret;

}